/*
 * Copyright (C) 2016 Bartosz Schiller.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.ashlikun.pdfview.util

import android.content.Context
import android.os.ParcelFileDescriptor
import android.util.Log
import android.util.TypedValue
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream

object PdfViewUtil {
    private const val DEFAULT_BUFFER_SIZE = 1024 * 4
    private const val TAG = "PDF_VIEW"
    var DEBUG_MODE = false

    /**
     * 缓存的大小（保留的位图数）
     */
    var CACHE_SIZE = 12
    var MAXIMUM_ZOOM = 10f
    var MINIMUM_ZOOM = 1f

    fun getDP(context: Context, dp: Int): Int {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp.toFloat(), context.resources.displayMetrics).toInt()
    }

    @Throws(IOException::class)
    fun toByteArray(inputStream: InputStream): ByteArray {
        val os = ByteArrayOutputStream()
        val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
        var n: Int
        while (-1 != inputStream.read(buffer).also { n = it }) {
            os.write(buffer, 0, n)
        }
        return os.toByteArray()
    }

    /**
     * 将InputStream转换为ParcelFileDescriptor。
     *
     * @param context     上下文，用于访问应用私有目录。
     * @param inputStream 要转换的InputStream。
     * @return ParcelFileDescriptor实例，指向包含输入流数据的临时文件。
     * @throws IOException 如果在文件操作过程中发生错误。
     */
    @Throws(IOException::class)
    fun inputStreamToParcelFileDescriptor(context: Context, inputStream: InputStream): ParcelFileDescriptor {
        // 创建一个临时文件
        val tempFile = File.createTempFile("pdf_temp" + System.currentTimeMillis(), "", context.cacheDir)
        try {
            FileOutputStream(tempFile).use { outputStream ->
                // 将InputStream的数据复制到临时文件
                val buffer = ByteArray(1024)
                var read: Int
                while (inputStream.read(buffer).also { read = it } != -1) {
                    outputStream.write(buffer, 0, read)
                }
                outputStream.flush() // 确保所有数据被写入文件
                // 使用临时文件创建ParcelFileDescriptor
                return ParcelFileDescriptor.open(tempFile, ParcelFileDescriptor.MODE_READ_ONLY)
            }
        } catch (e: IOException) {
            if (tempFile != null && tempFile.exists()) {
                tempFile.delete() // 删除临时文件以避免占用空间
            }
            // 重新抛出异常
            throw e
        }
    }

    /**
     * 将字节数组转换为ParcelFileDescriptor。
     *
     * @param context   上下文，用于访问应用私有目录。
     * @param byteArray 要转换的字节数组。
     * @return ParcelFileDescriptor实例，指向包含字节数据的临时文件。
     * @throws IOException 如果在文件操作过程中发生错误。
     */
    @Throws(IOException::class)
    fun byteArrayToParcelFileDescriptor(context: Context, byteArray: ByteArray?): ParcelFileDescriptor {
        // 创建一个临时文件
        val tempFile = File.createTempFile("pdf_temp" + System.currentTimeMillis(), "", context.cacheDir)
        try {
            FileOutputStream(tempFile).use { fos ->
                // 将字节数组写入临时文件
                fos.write(byteArray)
                fos.flush() // 确保所有数据被写入文件
                // 使用临时文件创建ParcelFileDescriptor
                return ParcelFileDescriptor.open(tempFile, ParcelFileDescriptor.MODE_READ_ONLY)
            }
        } catch (e: IOException) {
            if (tempFile != null && tempFile.exists()) {
                tempFile.delete() // 删除临时文件以避免占用空间
            }
            throw e // 重新抛出异常
        }
    }

    @Throws(IOException::class)
    fun fileFromAsset(context: Context, assetName: String): File {
        val outFile = File(context.cacheDir, "$assetName-pdfview.pdf")
        if (assetName.contains("/")) {
            outFile.parentFile.mkdirs()
        }
        copy(context.assets.open(assetName), outFile)
        return outFile
    }

    @Throws(IOException::class)
    fun copy(inputStream: InputStream?, output: File?) {
        var outputStream: OutputStream? = null
        try {
            outputStream = FileOutputStream(output)
            var read = 0
            val bytes = ByteArray(1024)
            while (inputStream!!.read(bytes).also { read = it } != -1) {
                outputStream.write(bytes, 0, read)
            }
        } finally {
            try {
                inputStream?.close()
            } finally {
                outputStream?.close()
            }
        }
    }

    fun limit(number: Float, between: Float, and: Float): Float {
        if (number <= between) return between
        return if (number >= and) and else number
    }

    fun loge(str: String) {
        Log.e(TAG, str)
    }

    fun logi(str: String) {
        Log.i(TAG, str)
    }
}
